import { createRef, forwardRef, useImperativeHandle, useRef, useState } from 'react';

import { Drawer, DrawerProps } from 'antd';

import { ElementsHolder, ElementsHolderRef } from '../elementsHolder';

export type HookDrawerProps = {
  afterClose: () => void;
  config: DrawerProps;
};
export type HookDrawerRef = {
  destroy: () => void;
  update: (config: DrawerProps) => void;
};

const HookDrawer = forwardRef<HookDrawerRef, HookDrawerProps>(
  ({ afterClose: hookAfterClose, config }, ref) => {
    const [open, setOpen] = useState(true);
    const [innerConfig, setInnerConfig] = useState(config);

    const afterClose: DrawerProps['afterOpenChange'] = (...args) => {
      if (args[0] === false) {
        hookAfterClose();
        innerConfig.afterOpenChange?.(...args);
      }
    };

    const close = () => {
      setOpen(false);
    };

    useImperativeHandle(ref, () => {
      return {
        destroy: close,
        update: (newConfig) => {
          setInnerConfig((prev) => ({
            ...prev,
            ...newConfig
          }));
        }
      };
    });

    return (
      <Drawer
        footer={null}
        {...innerConfig}
        open={open}
        onClose={close}
        afterOpenChange={afterClose}
      />
    );
  }
);

// ===========================

export type DrawerHookAPI = {
  open: (config?: DrawerProps) => {
    destroy: () => void;
    update: (config: DrawerProps) => void;
  };
};

let uuid = 0;

export const useDrawer = () => {
  const holderRef = useRef<ElementsHolderRef>(null);

  const fns: DrawerHookAPI = {
    open: (config) => {
      uuid += 1;
      const drawerRef = createRef<HookDrawerRef>();

      // eslint-disable-next-line prefer-const
      let closeFunc: (() => void) | undefined;

      const drawer = (
        <HookDrawer
          key={`drawer-${uuid}`}
          config={config || {}}
          ref={drawerRef}
          afterClose={() => {
            closeFunc?.();
          }}
        />
      );

      closeFunc = holderRef.current?.patchElement(drawer);

      return {
        destroy: () => {
          drawerRef.current?.destroy();
        },
        update: (newConfig: DrawerProps) => {
          drawerRef.current?.update(newConfig);
        }
      };
    }
  };

  return [fns, <ElementsHolder key="drawer-holder" ref={holderRef} />] as readonly [
    instance: DrawerHookAPI,
    contextHolder: React.ReactElement
  ];
};
